/*
 * Copyright (c) 2020, HiHope Community.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "ht30.h"

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "wifiiot_i2c.h"
#include "wifiiot_errno.h"

#define HT30_I2C_IDX WIFI_IOT_I2C_IDX_0

#define HT30_STARTUP_TIME     10// 上电启动时间
#define HT30_CALIBRATION_TIME 20// 初始化（校准）时间
#define HT30_MEASURE_TIME     40// 测量时间

#define HT30_DEVICE_ADDR   0x44
#define HT30_READ_ADDR     ((HT30_DEVICE_ADDR<<1)|0x1)
#define HT30_WRITE_ADDR    ((HT30_DEVICE_ADDR<<1)|0x0)

#define HT30_CMD_MSB       0x24 // 关闭Clock  stretching
#define HT30_CMD_LSB       0x16 // 低重复率


// 最大范围结果字节数（包含了温湿度测量结果）
#define HT30_STATUS_RESPONSE_MAX 6

// 获得的测量结果数据位 最大值
#define HT30_RESOLUTION            65535 // (1<<16) - 1  // 2^16 - 1

#define HT30_MAX_RETRY 10  // 最大重试次数

static uint32_t HT30_Read(uint8_t* buffer, uint32_t buffLen)
{
    WifiIotI2cData data = { 0 };
    data.receiveBuf = buffer;
    data.receiveLen = buffLen;
    uint32_t retval = I2cRead(HT30_I2C_IDX, HT30_READ_ADDR, &data);
    if (retval != WIFI_IOT_SUCCESS) {
        printf("I2cRead() failed, %0X!\n", retval);
        return retval;
    }
    return WIFI_IOT_SUCCESS;
}

static uint32_t HT30_Write(uint8_t* buffer, uint32_t buffLen)
{
    WifiIotI2cData data = { 0 };
    data.sendBuf = buffer;
    data.sendLen = buffLen;
    uint32_t retval = I2cWrite(HT30_I2C_IDX, HT30_WRITE_ADDR, &data);
    if (retval != WIFI_IOT_SUCCESS) {
        printf("I2cWrite(%02X) failed, %0X!\n", buffer[0], retval);
        return retval;
    }
    return WIFI_IOT_SUCCESS;
}

// 开始测量
uint32_t HT30_StartMeasure(void)
{
    uint8_t clibrateCmd[] = {HT30_CMD_MSB, HT30_CMD_LSB}; // 设置MSB和LSB
    return HT30_Write(clibrateCmd, sizeof(clibrateCmd));
}

// 接收测量结果，拼接转换为标准值
uint32_t HT30_GetMeasureResult(float* temp, float* humi)
{
    uint32_t retval = 0, i = 0;
    if (temp == NULL || humi == NULL) {
        return WIFI_IOT_FAILURE;
    }

    // 获得的返回数据
    uint8_t buffer[HT30_STATUS_RESPONSE_MAX];
    memset(&buffer, 0x0, sizeof(buffer));

    for (i = 0; i < HT30_MAX_RETRY; i++) {
        osDelay(HT30_MEASURE_TIME);
        retval = HT30_Read(buffer, sizeof(buffer));  // recv status command result
        if (retval == WIFI_IOT_SUCCESS) {
            break;
        }
        printf("HT30 device busy, retry %d/%d!\r\n", i, HT30_MAX_RETRY);
    }
    // 
    if (i >= HT30_MAX_RETRY) {
        printf("HT30 device always busy!\r\n");
        return WIFI_IOT_FAILURE;
    }

    // 获得温度数据
    uint32_t tempRaw = buffer[0];
    tempRaw = (tempRaw << 8) | buffer[1];
    *temp = tempRaw / (float)HT30_RESOLUTION * 175 - 45;

    // 获得湿度数据
    uint32_t humiRaw = buffer[3];
    humiRaw = (humiRaw << 8) | buffer[4];
    *humi = humiRaw / (float)HT30_RESOLUTION * 100;

    printf("humi = %04X, %f, temp= %04X, %f\r\n", humiRaw, *humi, tempRaw, *temp);
    return WIFI_IOT_SUCCESS;
}
